#include <sstream>
#include <iostream>
#include <fstream>
#include <wait.h>

#include <BaseException.h>
#include <Logger.h>
#include <Utils.h>
#include <FifoLectura.h>
#include <Serializable.h>
#include <Constantes.h>
#include <FifoEscritura.h>
#include <ConfigurationFile.h>
#include <Client.h>

const int SUCCESS_EXIT = 0;

using namespace std;


int main(int argc, char* argv[])
{
	int exitCode = SUCCESS_EXIT;
	Logger* log = NULL;
	pid_t pidId = 0;
	
	try
	{
		log = Logger::getInstance();
		
		std::string strPID = Utils::convertIntToStr(getpid());
		log->info("CLIENTE >> Proceso client launcher iniciado >> Cliente Launcher PID: " + strPID);
		
		int cantCliente = Utils::convertSrtToInt(ConfigurationFile::getProperty(Properties::CANT_CLIENTES));
		for(int i = 0 ; i < cantCliente; i++)
		{
			Utils::initializeSeed();
			pidId = fork();
			
			if(pidId == 0 )
			{
				Client client;
				std::string strPIDHijo = Utils::convertIntToStr(getpid());
				log->info("CLIENTE >> Proceso cliente iniciado >> Cliente PID: " + strPIDHijo);
				
				log->info("CLIENTE >> Abriendo cola de clientes del jefe");
				client.joinChiefClientQueue();
				
				log->info("CLIENTE >> Creando receptor de instrucciones");
				client.createInstructionReceptor();
				
				log->info("CLIENTE >> Registrando en cola de clientes del jefe");
				client.checkInAttQueue();
				
				log->info("CLIENTE >> Esperando a ser atendido o rechazado");
				std::string instruction = client.retrieveInstructions();
				
				if(client.shouldLeave(instruction))
				{
					log->info("CLIENTE >> Finalizar ejecucion");
				}
				else if(client.hasBeenAssisted(instruction))
				{
					log->info("CLIENTE >> Playero asignado >> Solicito combustible");
					client.askForGas(Utils::generateRandNumber());
					log->info("CLIENTE >> Carga completada >> Retirandose de la estacion");
				}
				else
				{
					throw BaseException("CLIENTE >> Instruccion no implementada");
				}
				break;
			}
			usleep(200000);
		}
	} catch (const BaseException& e) {
		std::cerr << "ERROR FATAL CLIENTE: " << e.what() << std::endl;
		exitCode = e.getCode();
		log->error(e.what());
	}
	
	if(pidId != 0)
	{
		if(log != NULL)
			log->info("CLIENTE >> Client Launcher, esperando a que los clientes finalicen");
		int estado;
		while( wait( (void*) &estado) > 0);
		
		if(log != NULL)
			log->info("CLIENTE >> Client Launcher, clientes finalizados");
	}
	
	Logger::destroy();
	return exitCode;
}

